home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / libs / unixlib.lha / unix / src / exec.c < prev    next >
C/C++ Source or Header  |  1996-07-07  |  6KB  |  216 lines

  1. #include "amiga.h"
  2. #include "processes.h"
  3. #include <amiga/ioctl.h>
  4. #include <exec/memory.h>
  5. #include <dos/dosextens.h>
  6. #include <dos/dostags.h>
  7. #include <string.h>
  8.  
  9. extern int ioctl(int fd, int request, void *data);
  10. int execf(int (*)(void *), void *, int, int, char *, int);
  11.  
  12. extern char *__procname;
  13.  
  14. /* Variables used by a child that is starting up */
  15. struct MemList *__near _child_entry;    /* Memory used for child's code */
  16. struct Message __near startup_message;
  17. struct exit_message *__near _child_exit;
  18. char *__near _child_command;
  19. int __near _child_command_len;
  20. char *__near _child_door_name;
  21. int __near _child_door_name_len;
  22. int (*__near _child_fp)(void *);
  23. extern char __far _child_startup, __far _child_startup_end;
  24.  
  25. int exec(char    *program,
  26.      char    **argv,
  27.      int    input,
  28.      int    output,
  29.      char    *dir,
  30.      int    stacksize)
  31. {
  32.     return(execf(NULL, (void *)argv, input, output, dir, stacksize));
  33. }
  34.  
  35. int execf(int (*fp)(void *),
  36.       void    *data,
  37.       int    input,
  38.       int    output,
  39.       char    *dir,
  40.       int    stacksize)
  41. {
  42.     int index, comsize;
  43.     int close_in = TRUE, close_out = TRUE;
  44.     int in_isfifo = FALSE, out_isfifo = FALSE;
  45.     char *combuf = NULL, *bp;
  46.     BPTR in, out, dirlock;
  47.     int stack = (stacksize > 0 ? stacksize : _stack_size);
  48.     char *procname = (__procname ? __procname : "New Process");
  49.     struct process *entry = malloc(sizeof(struct process));
  50.     static struct MemList alloc_child = { {0}, 1};
  51.     extern int _pseudo_close(int fd);
  52.  
  53.     /*  in & out must be different fhs for CreateNewProc. But get_fh
  54.      *  is not guaranteed to return different fhs when called twice on
  55.      *  the same file :-( Luckily it does for socketpairs.
  56.      *  Don't try & pass the same AmigaDOS file for input & output */
  57.  
  58.     if (input == -1) {
  59.     close_in = FALSE;
  60.     input = 0;
  61.     }
  62.     if (output == -1) {
  63.     close_out = FALSE;
  64.     output = 1;
  65.     }
  66.     if (ioctl(input, _AMIGA_GET_FH, &in) == -1 ||
  67.         ioctl(input, _AMIGA_IS_FIFO, &in_isfifo) == -1)
  68.     in = 0;
  69.     if (ioctl(output, _AMIGA_GET_FH, &out) == -1 ||
  70.         ioctl(output, _AMIGA_IS_FIFO, &out_isfifo) == -1)
  71.     out = 0;
  72.     if (close_in)
  73.     _pseudo_close(input);
  74.     if (close_out && input != output)
  75.     _pseudo_close(output);
  76.     if (in_isfifo)
  77.     close_in = TRUE;
  78.     if (out_isfifo)
  79.     close_out = TRUE;
  80.  
  81.     if (fp) {
  82.     _child_fp = fp;
  83.     } else {
  84.     _child_fp = NULL;
  85.     comsize = 256;
  86.     combuf = AllocMem(comsize, 0);
  87.     }
  88.  
  89.     _child_exit = AllocMem(sizeof(struct exit_message), 0);
  90.     _child_door_name = AllocMem(DOOR_LEN, 0);
  91.  
  92.     alloc_child.ml_ME[0].me_Length = &_child_startup_end - &_child_startup;
  93.     _child_entry = AllocEntry(&alloc_child);
  94.  
  95.     if (entry && in && out && (combuf || fp) && _child_exit &&
  96.     _child_door_name && (long) _child_entry > 0)
  97.     {
  98.     memcpy(_child_entry->ml_ME[0].me_Addr, &_child_startup,
  99.            _child_entry->ml_ME[0].me_Length);
  100.     strcpy(_child_door_name, _door_name);
  101.     _child_door_name_len = DOOR_LEN;
  102.     if (!fp) {
  103.         char **argv = data;
  104.         bp = combuf;
  105.         for (index = 0; argv[index] != 0; index++) {
  106.         char *s = argv[index];
  107.         int len;
  108.  
  109.         len = 3;
  110.         while (*s)
  111.             len += 1 + 2 * (*s++ == '"');
  112.         if (bp + len + 1 >= combuf + comsize) {
  113.             char *newbuf;
  114.             int new_comsize;
  115.  
  116.             new_comsize = 2 * comsize + len;
  117.             newbuf = AllocMem(new_comsize, 0);
  118.             if (!newbuf) {
  119.             errno = ENOMEM;
  120.             goto error;
  121.             }
  122.             memcpy(newbuf, combuf, comsize);
  123.  
  124.             bp = newbuf + (bp - combuf);
  125.             combuf = newbuf;
  126.             comsize = new_comsize;
  127.         }
  128.         *bp++ = ' ';
  129.         *bp++ = '"';
  130.         s = argv[index];
  131.         while (*s) {
  132.             if (*s == '"' || *s == '*')
  133.             *bp++ = '*';
  134.             *bp++ = *s++;
  135.         }
  136.         *bp++ = '"';
  137.         }
  138.         *bp = '\0';
  139.     }
  140.     if (dir)
  141.         dirlock = Lock(dir, SHARED_LOCK);
  142.     else {
  143.         BPTR cd = CurrentDir(0);
  144.  
  145.         dirlock = DupLock(cd);
  146.         CurrentDir(cd);
  147.     }
  148.     if (dirlock) {
  149.         entry->pid = _next_pid++;
  150.         entry->input = in;
  151.         if (fp) {
  152.             _child_command = (char *)data;
  153.         _child_command_len = 0;
  154.         } else {
  155.         _child_command = combuf;
  156.         _child_command_len = comsize;
  157.         }
  158.  
  159.         /* This message is sent by the child when it has started */
  160.         startup_message.mn_Length = sizeof(startup_message);
  161.         startup_message.mn_Node.ln_Type = NT_MESSAGE;
  162.  
  163.         /* This message is sent by the child when it exits */
  164.         _child_exit->m.mn_Length = sizeof(*_child_exit);
  165.         _child_exit->m.mn_Node.ln_Type = NT_MESSAGE;
  166.         _child_exit->pid = entry->pid;
  167.  
  168.         /* Flush the data cache in case we're on a 68040 */
  169.         CacheClearU();
  170.  
  171.         entry->process = CreateNewProcTags(NP_Entry, _child_entry->ml_ME[0].me_Addr,
  172.                            NP_Name,        procname,
  173.                            NP_Input,    in,
  174.                            NP_CloseInput,    close_in,
  175.                            NP_Output,    out,
  176.                            NP_CloseOutput,    close_out,
  177.                            NP_StackSize,    stack,
  178.                            NP_CurrentDir,    dirlock,
  179.                            NP_Cli,        TRUE,
  180.                            TAG_END);
  181.         if (entry->process) {
  182.         do
  183.             WaitPort(_startup_port);
  184.         while (!GetMsg(_startup_port));
  185.         entry->status = alive;
  186.         AddHead((struct List *) &_processes, (struct Node *) entry);
  187.         return entry->pid;
  188.         }
  189.     }
  190.     errno = convert_oserr(IoErr());
  191.     if (!fp)
  192.         FreeMem(combuf, comsize);
  193.     free(entry);
  194.     if (dirlock)
  195.         UnLock(dirlock);
  196.     } else {
  197.     if (in && out)
  198.         errno = ENOMEM;
  199.     }
  200.  
  201.   error:
  202.     if (in && close_in)
  203.     Close(in);
  204.     if (out && close_out)
  205.     Close(out);
  206.     if (combuf)
  207.     FreeMem(combuf, comsize);
  208.     if (_child_exit)
  209.     FreeMem(_child_exit, sizeof(struct exit_message));
  210.     if (_child_door_name)
  211.     FreeMem(_child_door_name, DOOR_LEN);
  212.     if ((long) _child_entry > 0)
  213.     FreeEntry(_child_entry);
  214.     return -1;
  215. }
  216.